package utils

//简单组合运算
func Combine(src []int, combineCount int, fn func([]int) bool) [][]int {
	ret, _ := combineImpl(src, []int{}, combineCount, fn)
	return ret
}

func combineImpl(src []int, dest []int, combineCount int, fn func([]int) bool) ([][]int, bool) {
	if 1 == (combineCount - len(dest)) {
		ret := make([][]int, len(src))
		for k, v := range src {
			ret[k] = append(dest, v)
			if nil != fn && fn(ret[k]) {
				return [][]int{}, true
			}
		}

		return ret, false
	}

	var ret [][]int
	for k, v := range src {
		tempDest := make([]int, len(dest)+1)
		copy(tempDest, dest)
		tempDest[len(dest)] = v
		//tempDest := append(dest, v)
		tempRet, isStop := combineImpl(src[k+1:], tempDest, combineCount, fn)
		if isStop {
			return [][]int{}, true
		}
		ret = append(ret, tempRet...)
	}

	return ret, false
}

//带tag的组合运算，对CombineNode中的dta字段进行组合，Tag是为Data绑定的标签
type CombineNode struct {
	Data int
	Tag  interface{}
}

func CombineEx(src []CombineNode, combineCount int, fn func([]CombineNode) bool) [][]CombineNode {
	ret, _ := combineImplEx(src, []CombineNode{}, combineCount, fn)
	return ret
}

func combineImplEx(src []CombineNode, dest []CombineNode, combineCount int, fn func([]CombineNode) bool) ([][]CombineNode, bool) {
	if 1 == (combineCount - len(dest)) {
		ret := make([][]CombineNode, len(src))
		for k, v := range src {
			ret[k] = append(dest, v)
			if nil != fn && fn(ret[k]) {
				return [][]CombineNode{}, true
			}
		}

		return ret, false
	}

	var ret [][]CombineNode
	for k, v := range src {
		tempDest := make([]CombineNode, len(dest)+1)
		copy(tempDest, dest)
		tempDest[len(dest)] = v
		//tempDest := append(dest, v)
		tempRet, isStop := combineImplEx(src[k+1:], tempDest, combineCount, fn)
		if isStop {
			return [][]CombineNode{}, true
		}
		ret = append(ret, tempRet...)
	}

	return ret, false
}
